#ifndef PARTBOUNDCOND_H
#define PARTBOUNDCOND_H

#include "../Input/PicParams.h"
#include "CellParticles.h"
#include "../Tool/Log.h"

class ParallelMPI;

// --------------------------------------------------------------------------------------------------------------------
//Class PartBoundCond
// --------------------------------------------------------------------------------------------------------------------
template<int dim>
class PartBoundCond 
{
public:
    //partBoundCond creator, (default no MPI set)
    PartBoundCond(PicParams* params_, ParallelMPI* pmpi_, int ispec);
    //partBoundCond destructor
    ~PartBoundCond();

    //West particles boundary conditions pointers (same prototypes for all conditions)
    //@see BoundaryConditionType.h for functions that this pointers will target
    int (*bc_west)  (Particle<dim> &particle, double limit_pos, int i_dim);
    //East particles boundary conditions pointers
    int (*bc_east)  (Particle<dim> &particle, double limit_pos, int i_dim);
    //South particles boundary conditions pointers
    int (*bc_south) (Particle<dim> &particle, double limit_pos, int i_dim);
    //North particles boundary conditions pointers
    int (*bc_north) (Particle<dim> &particle, double limit_pos, int i_dim);
    //Bottom particles boundary conditions pointers
    int (*bc_bottom)(Particle<dim> &particle, double limit_pos, int i_dim);
    //Up particles boundary conditions pointers
    int (*bc_up)    (Particle<dim> &particle, double limit_pos, int i_dim);

    //Method which applies particles boundary conditions.
    //If the MPI process is not a border process, particles will be flagged as an exchange particle returning 0
    //Conditions along X are applied first, then Y, then Z.
    //The decision whether the particle is added or not on the Exchange Particle List is defined by the final
    //value of keep_part.
    //Be careful, once an a BC along a given dimension set keep_part to 0, it will remain to 0.
    //keep_particle = :  0 delete; 1 MPI change; 2 move to other cell; 3 still in the cell
    inline int apply(Particle<dim> &particle) 
    {
        int keep_part;
        if(particle.position[0] < x_min) 
        {
            if(bc_west == NULL)
            {
                keep_part = 1;
            }
            else 
            {
                keep_part = (*bc_west)(particle,2.*x_min, 0);
            }
        }
        else if( particle.position[0] >= x_max) 
        {
            if(bc_east==NULL)
            {
                keep_part = 1;
            }
            else 
            {
                keep_part = (*bc_east)(particle, 2.*x_max, 0);
            }
        }
        if(n_dim_field >= 2)
        {
            if(particle.position[1] < y_min)
            {
                if(bc_south==NULL)
                {
                    keep_part = 1;
                }
                else 
                {
                    keep_part = (*bc_south)(particle, 2.*y_min, 1);
                }
            }
            else if(particle.position[1] >= y_max) 
            {
                if(bc_north==NULL)
                {
                    keep_part = 1;
                }
                else 
                {
                    keep_part = (*bc_north)(particle, 2.*y_max, 1);
                }
            }

            if(n_dim_field == 3)
            {
                if(particle.position[2] < z_min) 
                {
                    if(bc_bottom==NULL)
                    {
                        keep_part = 1;
                    }
                    else 
                    {
                        keep_part = (*bc_bottom)(particle, 2.*z_min, 2);
                    }
                }
                else if(particle.position[2] >= z_max) 
                {
                    if(bc_up==NULL)
                    {
                        keep_part = 1;
                    }
                    else 
                    {
                        keep_part = (*bc_up)(particle, 2.*z_max, 2);
                    }
                }
            }
        }

        return keep_part;
    };

    PicParams* params;
    ParallelMPI* pmpi;


private:
    //Min value of the x coordinate of particles on the current processor
    //Real value, oversize is not considered (same for all)
    double x_min;
    //Max value of the x coordinate of particles on the current processor
    double x_max;
    //Min value of the y coordinate of particles on the current processor
    double y_min;
    //Max value of the y coordinate of particles on the current processor
    double y_max;
    //Min value of the z coordinate of particles on the current processor
    double z_min;
    //Max value of the z coordinate of particles on the current processor
    double z_max;

    //Space dimension of a particle
    int n_dim_field;

};

#endif
